package com.example.inventory.service;

import com.example.inventory.messaging.message.OrderCreatedMessage;
import com.example.inventory.model.entity.InventoryLog;
import com.example.inventory.model.entity.ProductSku;
import com.example.inventory.repository.InventoryLogRepository;
import com.example.inventory.repository.ProductSkuRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 库存服务实现类
 * 
 * @author mall-team
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InventoryService {

    private final ProductSkuRepository productSkuRepository;
    private final InventoryLogRepository inventoryLogRepository;

    /**
     * 预留库存
     * 1. 检查库存是否充足
     * 2. 预留库存（增加 reserved_quantity）
     * 3. 记录库存操作日志
     * 
     * @param orderMessage 订单创建消息
     * @throws RuntimeException 库存不足时抛出异常
     */
    @Transactional(rollbackFor = Exception.class)
    public void reserveStock(OrderCreatedMessage orderMessage) {
        log.info("开始预留库存: orderNo={}", orderMessage.getOrderNo());

        for (OrderCreatedMessage.OrderItemInfo item : orderMessage.getItems()) {
            // 1. 使用悲观锁查询SKU，防止并发问题
            ProductSku sku = productSkuRepository.findByIdWithLock(item.getSkuId())
                    .orElseThrow(() -> new RuntimeException(
                            String.format("SKU不存在: skuId=%d", item.getSkuId())));

            // 2. 检查可用库存是否充足
            Integer availableQuantity = sku.getAvailableQuantity();
            if (availableQuantity < item.getQuantity()) {
                throw new RuntimeException(
                        String.format("库存不足: skuId=%d, skuName=%s, 需要=%d, 可用=%d",
                                sku.getId(), sku.getSkuName(), item.getQuantity(), availableQuantity));
            }

            // 3. 预留库存
            Integer beforeReserved = sku.getReservedQuantity();
            sku.setReservedQuantity(beforeReserved + item.getQuantity());
            productSkuRepository.save(sku);

            log.info("库存预留成功: skuId={}, skuName={}, 预留数量={}, 预留前={}, 预留后={}",
                    sku.getId(), sku.getSkuName(), item.getQuantity(),
                    beforeReserved, sku.getReservedQuantity());

            // 4. 记录库存操作日志
            InventoryLog log = InventoryLog.builder()
                    .skuId(sku.getId())
                    .orderNo(orderMessage.getOrderNo())
                    .operationType("RESERVE")
                    .quantity(item.getQuantity())
                    .beforeQuantity(beforeReserved)
                    .afterQuantity(sku.getReservedQuantity())
                    .remark(String.format("订单 %s 预留库存", orderMessage.getOrderNo()))
                    .build();
            inventoryLogRepository.save(log);
        }

        log.info("订单库存预留完成: orderNo={}", orderMessage.getOrderNo());
    }

    /**
     * 扣减库存（支付成功后调用）
     * 1. 减少实际库存数量
     * 2. 减少预留库存数量
     * 3. 记录库存操作日志
     * 
     * @param orderNo 订单编号
     * @param skuId SKU ID
     * @param quantity 扣减数量
     */
    @Transactional(rollbackFor = Exception.class)
    public void deductStock(String orderNo, Long skuId, Integer quantity) {
        log.info("开始扣减库存: orderNo={}, skuId={}, quantity={}", orderNo, skuId, quantity);

        // 1. 使用悲观锁查询SKU
        ProductSku sku = productSkuRepository.findByIdWithLock(skuId)
                .orElseThrow(() -> new RuntimeException("SKU不存在: " + skuId));

        // 2. 扣减实际库存
        Integer beforeStock = sku.getStockQuantity();
        sku.setStockQuantity(beforeStock - quantity);

        // 3. 减少预留库存
        Integer beforeReserved = sku.getReservedQuantity();
        sku.setReservedQuantity(beforeReserved - quantity);

        productSkuRepository.save(sku);

        log.info("库存扣减成功: skuId={}, 扣减数量={}, 库存: {}→{}, 预留: {}→{}",
                skuId, quantity, beforeStock, sku.getStockQuantity(),
                beforeReserved, sku.getReservedQuantity());

        // 4. 记录库存操作日志
        InventoryLog log = InventoryLog.builder()
                .skuId(skuId)
                .orderNo(orderNo)
                .operationType("DEDUCT")
                .quantity(quantity)
                .beforeQuantity(beforeStock)
                .afterQuantity(sku.getStockQuantity())
                .remark(String.format("订单 %s 扣减库存", orderNo))
                .build();
        inventoryLogRepository.save(log);
    }

    /**
     * 释放库存（订单取消时调用）
     * 1. 减少预留库存数量
     * 2. 记录库存操作日志
     * 
     * @param orderNo 订单编号
     * @param skuId SKU ID
     * @param quantity 释放数量
     */
    @Transactional(rollbackFor = Exception.class)
    public void releaseStock(String orderNo, Long skuId, Integer quantity) {
        log.info("开始释放库存: orderNo={}, skuId={}, quantity={}", orderNo, skuId, quantity);

        // 1. 使用悲观锁查询SKU
        ProductSku sku = productSkuRepository.findByIdWithLock(skuId)
                .orElseThrow(() -> new RuntimeException("SKU不存在: " + skuId));

        // 2. 减少预留库存
        Integer beforeReserved = sku.getReservedQuantity();
        sku.setReservedQuantity(beforeReserved - quantity);
        productSkuRepository.save(sku);

        log.info("库存释放成功: skuId={}, 释放数量={}, 预留: {}→{}",
                skuId, quantity, beforeReserved, sku.getReservedQuantity());

        // 3. 记录库存操作日志
        InventoryLog log = InventoryLog.builder()
                .skuId(skuId)
                .orderNo(orderNo)
                .operationType("RELEASE")
                .quantity(quantity)
                .beforeQuantity(beforeReserved)
                .afterQuantity(sku.getReservedQuantity())
                .remark(String.format("订单 %s 释放库存", orderNo))
                .build();
        inventoryLogRepository.save(log);
    }
}

